//CS362 - Team 18
/* systemTest.c
 * this file runs 2 separate system tests with different buy and action priorities.
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include "testUtilities.h"
#include "randomGenerator.h"
#include "rngs.h" 

// This function serves as the AI
void makeMove(struct gameState *state, int player, FILE * file){
	int i = 0, j = 0;
	int pickActionCard = -1;
	int pickBuyCard = -1;
	int handPosition = -1;
	int playResult = 0;
	int buyResult = -1;
	char cardName[MAX_STRING_LENGTH];
	// Action Phase
	fprintf(file, "Player %d begin ACTION PHASE.  Actions available: %d\n", player, state->numActions);
	while(state->numActions > 0){
		for(i = 0; i < state->handCount[player]; i++){ // Loop through players hand
			for(j = 0; j < 10; j++){ // Loop through playable action cards
				if(state->hand[player][i] == actionPriority[j]){ // If player has card
					handPosition = i; // grab hand index to play card
					pickActionCard = state->hand[player][i];
					cardNumToName(pickActionCard, cardName);
					fprintf(file, "Found Action Card: %s\n", cardName);
					break;
				}
			}
		}

		if(pickActionCard == -1){ // if no playable action cards
			break;
		}else{
			fprintf(file, "Playing %s card.\n", cardName);
			playResult = playActionCard(state, player, pickActionCard, handPosition);
			if(playResult == -1){
				fprintf(file, "ERROR: Could not play %s card.  Action wasted.\n", cardName);
			}
		}
		// reset values
		pickActionCard = -1;
		handPosition = -1;
	}
	fprintf(file, "Player %d ACTION PHASE complete!\n", player);
	_printHand(player, state, file);

	// Buy Phase
	fprintf(file, "Player %d begin BUY PHASE. Buys available: %d\n", player, state->numBuys);
	while(state->numBuys > 0){
		for(i = 0; i < 15; i++){
			// if we have enough coins to buy the top priority card, buy it.
			// there should be cards available as well
			if(state->coins >= getCost(buyPriority[i]) && supplyCount(buyPriority[i], state) > 0){
				pickBuyCard = buyPriority[i];
			}
		}
		if(pickBuyCard > -1){
			buyResult = buyCard(pickBuyCard, state);
			if(buyResult == 0){
				cardNumToName(pickBuyCard, cardName);
				fprintf(file, "Player %d will buy: %s card.\n", player, cardName);
			}

		}else{
			fprintf(file, "Nothing purchased.\n");
			break; // no cards to buy
		}
		pickBuyCard = -1;
	}

}

int playActionCard(struct gameState *state, int player, int card, int handPos, FILE * file){
	int i = 0;
	int choice1 = -1;
	int choice2 = -1;
	int choice3 = -1;
	int cardCost = 0;
	int randomChoice = -1;
	int inventoryCheck = 0;
	char cardName[MAX_STRING_LENGTH];

	// Process through all possible action cards
	switch(card){
		case adventurer:
			playCard(handPos, 0, 0, 0, state);
			break;
		case council_room:
			playCard(handPos, 0, 0, 0, state);
			break;
		case feast:
			// Feast is used to buy a card costing up to 5 coins.
			// choice1 is the supply # of card desired/gained.
			// choice will be based on buyPriority
			for(i = 0; i < 15; i++){
				if(getCost(buyPriority[i]) < 6){
					choice1 = buyPriority[i];
				}
			}
			if(choice1 > -1){
				playCard(handPos, choice1, 0, 0, state);
			}else{
				return -1;
			}
			break;
		case gardens:
			// Gardens is not a playable card, but can still be selected.
			playCard(handPos, 0, 0, 0, state);
			break;
		case mine:
			// Mine is a trash for benefit card focused on:
			// 	-Trashing copper to gain silver.
			// 	-Trashing silver to gain gold.
			// choice1 is hand index of money to trash.
			// choice2 is supply card # (for silver & gold)
			for(i = 0; i < state->handCount[player]; i++){
				if(state->hand[player][i] == copper){
					choice1 = i; // provide hand position of copper card
					choice2 = silver; // plan to add a silver
				}else if(state->hand[player][i] == silver){
					choice1 = i; // proivde hand position of silver card
					choice2 = gold; // plan to add a gold
				}
			}

			if(choice1 > -1){ // do we have a copper to replace?
				playCard(handPos, choice1, choice2, 0, state);
			}else{
				return -1; // no treasure cards to select, card was burned
			}

			// do we need to trash the card?  dominion should handle this.
			break;
		case remodel:
			// choice1 is hand# of card to remodel (a card to trash that's not the remodel played)
			// choice2 is the supply # for card gained

			// Trash the lowest costing card from hand:
			for(i = 0; i < state->handCount[player]; i++){
				if(i == handPos){
					break; // cannot discard current remodel card
				}else{
					if(cardCost < getCost(state->hand[player][i])){
						cardCost = getCost(state->hand[player][i]);
						choice1 = i; // choice1 is the hand index #
					}
				}
			}

			// Identify a card to purchase that is trashed cost +2
			for(i = 0; i < 24; i++){
				// if the trashed card + 2 can cover the priority card, pick it!
				if(cardCost + 2 >= getCost(buyPriority[i])){
					choice2 = buyPriority[i];
				}
			}
			playCard(handPos, choice1, choice2, 0, state);
			break;
		case smithy:
			playCard(handPos, 0, 0, 0, state);
			break;
		case village:
			playCard(handPos, 0, 0, 0, state);
			break;
		case baron:
			// choice1 is boolean for discard of estate
			// cardEffect already handles the boolean cases
			choice1 = -1;

			// Determine if estate is present
			for(i = 0; i < state->handCount[player]; i++){
				if(state->hand[player][i] == estate){
					choice1 = 1;
				}
			}
			playCard(handPos, choice1, 0, 0, state);
			break;
		case great_hall:
			playCard(handPos, 0, 0, 0, state);
			break;
		case minion:
			// choice1 will add 2 coins
			// choice2 will discard hand, +4 cards, and other players with +5 cards
			//	will discard their hand & draw 4 new cards
			randomChoice = rand() % 2; // lets randomize this choice
			if(randomChoice == 0){
				choice1 = 1;
				choice2 = 0;
			}else if(randomChoice == 1){
				choice1 = 0;
				choice2 = 1;
			}else{
				return -1;
			}
			playCard(handPos, choice1, choice2, 0, state);
			break;
		case steward:
			// choice1 is to add 2 cards.
			// choice2 is to add 2 coins.
			// choice3 is to trash 2 cards.
			randomChoice = rand() % 3; // lets randomize this choice
			if(randomChoice == 0){
				choice1 = 1;
				choice2 = 0;
				choice3 = 0;
			}else if(randomChoice == 1){
				choice1 = 0;
				choice2 = 1;
				choice3 = 0;
			}else if(randomChoice == 2){
				choice1 = 0;
				choice2 = 0;
				choice3 = 1;
			}else{
				return -1;
			}
			playCard(handPos, choice1, choice2, choice3, state);
			break;
		case tribute:
			playCard(handPos, 0, 0, 0, state);
			break;
		case ambassador:
			// choice1 is the hand index #
			// choice2 is the number to return to supply
			choice1 = -1;
			choice2 = 0;

			// Attempt to find a COPPER card from hand
			for(i = 0; i < state->handCount[player]; i++){
				if(state->hand[player][i] == copper){
					choice1 = i;
					choice2++;
				}
			}
			if(choice2 > 2) choice2 = 2; // enforce cap at 2 copies to return
			playCard(handPos, choice1, choice2, 0, state); // line might be problematic
			break;
		case cutpurse:
			playCard(handPos, 0, 0, 0, state);
			break;
		case embargo:
			// choice1 is the supply #
			// play embargo on a buyPriority card
			for(i = 0; i < 15; i++){
				inventoryCheck = supplyCount(buyPriority[i], state);
				if(inventoryCheck < 1){ // don't embargo empty supply cards
					continue;
				}else{
					choice1 = buyPriority[i];
					break;
				}
			}
			playCard(handPos, choice1, 0, 0, state);
			cardNumToName(choice1, cardName);
			fprintf(file, "Embargo placed on %s\n", cardName);
			break;
		case outpost:
			playCard(handPos, 0, 0, 0, state);
			break;
		case salvager:
			// choice1 is the hand index to trash
			// Strategy suggests trashing highest costing card
			for(i = 0; i < state->handCount[player]; i++){
				if(cardCost < getCost(state->hand[player][i])){
					cardCost = getCost(state->hand[player][i]);
					choice1 = i;
				}
			}
			playCard(handPos, choice1, 0, 0, state);
			break;
		case sea_hag:
			playCard(handPos, 0, 0, 0, state);
			break;
		case treasure_map:
			// FUTURE CONSIDERATION - Treasure Map should only be played
			//	if 2 treasure maps exist in hand.
			playCard(handPos, 0, 0, 0, state);
			break;
		default:
			cardNumToName(card, cardName);
			fprintf(file, "ERROR: Cannot play %s card.\n", cardName);
			break;
	}
	return 0;
}

int playDominion(FILE * file){
	int i = 0;
	int seed = 0;
	int numPlayers = 0;
	int activePlayer = 0;
	char cardName[MAX_STRING_LENGTH];
	struct gameState state;
	int kingdom_cards[10]; // allocation for 10 kingdom cards
	//int winner_check = 0;

	// create random kingdom cards
	makeRandomKingdomCards(&state, kingdom_cards);
	//printf("Verifying Kingdom Cards:\n");
	numPlayers = makeRandomNumPlayers(&state, numPlayers);
	//printf("Number of Players for Game: %d\n", numPlayers);

	seed = makeRandomSeed(seed);
	initializeGame(numPlayers, kingdom_cards, seed, &state);
	fprintf(file, "Game Initialized with %d players and the following Kingdom cards: \n", numPlayers);
	for(i = 0; i < 10; i++){
		cardNumToName(kingdom_cards[i], cardName);
		fprintf(file, "%d: %s\n", i+1, cardName);
	}
	makeRandomPlayPriorities(kingdom_cards, file);
	fprintf(file, "BEGIN GAME\n");
	//printf("SCORE VERIFICATION\n");
	//printScores(&state);
	
	while(!isGameOver(&state)){
		activePlayer = whoseTurn(&state);
		//printf("Player %d's turn:\n", activePlayer);
		_printState(&state, file);
		makeMove(&state, activePlayer, file);	//player action & buy phase
		fprintf(file, "Player %d ends turn.\n", activePlayer);
		fprintf(file, "SCORE UPDATE\n");
		_printScores(&state, file);
		endTurn(&state); // cleanup phase
	}
	fprintf(file, "GAME OVER!  Calculating Results\n");
	for(i = 0; i < numPlayers; i++){
		fprintf(file, "Player %d score: %d\n", i+1, scoreFor(i, &state));
	}
	// get Winners has a bug!
	//winner_check = getWinners(&numPlayers, &state);
	//printf("Winner result: %d\n", winner_check);
	
	//free(&state); // cleanup game state
	//free(kingdom_cards); // cleanup kingdom cards
	return 0;
}

int main(int argc, char* argv[]) {
	struct gameState G;
	int k[NUM_K_CARDS];			//kingdom card array
	int seed = 1000;	//random seed
	int games = 10;		//games to be player
	int numPlayers, turnNum, player, i = 0;
	FILE * resultFile;
	
	resultFile = fopen ("gameResults.out","w");
	
/************************************** test 1 start **********************************/
	//beginning prints
	printf("starting testdominion.c...\n");
	printf("number of games: %d\nseed: %d\n", games, seed);
	
	//beginning prints for gameResults.out
	fprintf(resultFile, "starting testdominion.c...\n");
	fprintf(resultFile, "number of games: %d\nseed: %d\n", games, seed);
	
	srand(seed);
	for(i = 1; i < (games + 1);i++){
		printf("\nGame %d start:\n", i);
		fprintf(resultFile, "\nGame %d start:\n", i);
		while(1){	//sets players from 2-4
			//printf("we're trying to set players\n");
			numPlayers = (rand() % 3) + 2;
			if(numPlayers < 5 && numPlayers > 1){
				break;
			}
			//printf("numPlayers = %d\n", numPlayers);
		}
		
		fprintf(resultFile, "numPlayers = %d\n", numPlayers);
		selectKingdomCards(rand(), k);			//pick random kingdom cards
		_printKingdomCards(k, resultFile);					//print to resultFile
		initializeGame(numPlayers,k,1,&G);		
		while(!isGameOver(&G)){
			advBotTurn(&G, k, resultFile);
		}
		//end game prints
		printf("Game %d is over.\n", i);
		fprintf(resultFile, "Game %d is over.\n\n", i);
		_printSupply(&G, resultFile);						//supply count to resultFile
		_printScores(&G, resultFile);						//player scores to resultFile
		
	}
	
	printf("\nend of system test 1.\n");
/******************************** test 2 start ****************************************/ 	
	printf("\nstarting system test 2.\n");
	playDominion(resultFile);
	printf("end system test 2.\n");
/******************************** test 2 end ******************************************/
	
	printf("All tests completed successfully!\n\n");
		
	return 0;
}